package math;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class MathUtils {

	public static <K> K mode(List<K>  inputList){
		Map<K , Integer> quantityMap = new HashMap<K, Integer>();
		for(K element : inputList){
			Integer quantity = quantityMap.get(element);
			if(quantity == null){
				quantityMap.put(element, 1);
			}else{				
				quantityMap.put(element, ++quantity);
			}
		}
		
		K key = null;
		int value = 0;
		for(Entry<K,Integer> e : quantityMap.entrySet()){
			if(e.getValue() > value){
				key = e.getKey();
				value = e.getValue();
			}
		}		
		return key;		
	}

	public static <K extends Number> Number mean(List<K>  in){
		double total = 0.0;
		for(K element : in){
			total += element.doubleValue();
		}
		
		return total / in.size();		
	}
	
	@SuppressWarnings("unchecked")
	public static  <K extends Integer> Number median(final List<K>  in){
		List<K> sortedList = new ArrayList<K>(in);
		Collections.sort(sortedList);
		int size = sortedList.size();
		if(size%2==0){
			return sortedList.get(size/2);
		}else{
			List<K> middleVals = new ArrayList<K>();
			middleVals.add(sortedList.get(size/2));
			middleVals.add(sortedList.get((size/2)+1));
			return mean(middleVals);
		}
	}
	
	public static void main(String [] args){
		List<Integer> test = new ArrayList<Integer>();
		test.add(3);		
		test.add(3);
		test.add(1);
		test.add(2);
		test.add(2);
		test.add(4);
		test.add(3);
		test.add(4);
		test.add(4);
		test.add(4);

		System.out.println("Expected: 4, Actual: "+mode(test));
		System.out.println("Expected: 3, Actual: "+mean(test) );
		System.out.println("Expected: 3, Actual: "+median(test) );

	}
	
}
